package com.git.hui.yinshua.biz.common.wx;

import com.alibaba.fastjson.JSONObject;
import com.git.hui.yinshua.api.model.ExceptionUtil;
import com.git.hui.yinshua.common.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * @author YiHui
 * @date 2024/6/11
 */
@Slf4j
@Service
public class WxUserHelper {
    private static final String LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code";
    private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";

    private static final String PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";

    @Value("${wx.appId:}")
    private String appId;
    @Value("${wx.appSecret:}")
    private String appSecret;

    private RestTemplate restTemplate;

    public WxUserHelper() {
        restTemplate = new RestTemplate();
    }

    public ImmutablePair<String, String> getWxId(String code) {
        String response = restTemplate.getForObject(LOGIN_URL, String.class, MapUtil.newMap("appid", appId, "secret", appSecret, "code", code));
        log.info("获取用户的唯一标识: {}", response);
        JSONObject obj = JSONObject.parseObject(response);
        if (obj == null) {
            throw ExceptionUtil.newBizException("登录失败!");
        }

        Integer errCode = obj.getInteger("errcode");
        if (errCode != null && errCode != 0) {
            throw ExceptionUtil.newBizException("登录失败:" + obj.getString("errmsg"));
        }

        String openId = obj.getString("openid");
        String unionId = obj.getString("unionid");
        return ImmutablePair.of(unionId == null ? openId : unionId, openId);
    }

    /**
     * 返回用户手机号
     *
     * @param code 验证码
     * @return 用户手机号信息
     */
    public String getPhone(String code) {
        this.accessToken = getAccessToken();
        Map<String, String> params = new HashMap<>();
        params.put("code", code);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<Map<String, String>> entity = new org.springframework.http.HttpEntity<>(params, headers);
        String ans = restTemplate.postForObject(PHONE_URL + this.accessToken, entity, String.class);
        log.info("获取的用户手机号信息: {}", ans);
        return ans;
    }


    private String accessToken;
    private long expireAt = 0;

    private void refreshToken() {
        long now = System.currentTimeMillis();
        String response = restTemplate.getForObject(TOKEN_URL, String.class, MapUtil.newMap("appid", appId, "secret", appSecret));
        log.info("用户token获取： {}", response);
        JSONObject obj = JSONObject.parseObject(response);
        this.accessToken = obj.getString("access_token");
        Long expireSeconds = obj.getLong("expires_in");
        this.expireAt = now + expireSeconds * 1000;
    }

    /**
     * 获取访问的accessToken
     *
     * @return
     */
    public String getAccessToken() {
        long now = System.currentTimeMillis();
        if (now > expireAt + 300_000) {
            refreshToken();
        }
        return this.accessToken;
    }

    /**
     * 十分钟执行一次
     */
    @Scheduled(fixedRate = 600_000, initialDelay = 60_000)
    public void autoRefresh() {
        try {
            long now = System.currentTimeMillis();
            if (now > expireAt + 900_000) {
                // 还有十五分钟过期，就提前刷新访问token
                this.refreshToken();
            }
        } catch (Exception e) {
            log.error("自动刷新小程序访问token失败!", e);
        }
    }

}
